##########################################
## Copyright 2012-2013 Ceruti Francesco
##
##
## This file is part of LiSP (Linux Show Player).
##
## LiSP (Linux Show Player) is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## LiSP (Linux Show Player) is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public  License
## along with LiSP (Linux Show Player).  If not, see <http://www.gnu.org/licenses/>.
##########################################

import gi
gi.require_version('Gst', '1.0')
import sys
import lisp.plugin as plugin
import lisp.layout as layout

from PyQt4 import QtGui
from gi.repository import GObject, Gst
from copy import deepcopy

from lisp.ui.mainwindow import MainWindow
from lisp.ui.layoutselect import LayoutSelect
from lisp.ui import styles
from lisp.layout.qmediawidget import QMediaWidget
from lisp.core.collector import Collector
from lisp.core.media import Media
from lisp._xml import xml_reader, xml_writer
from lisp.utils.progress import Progress
from lisp.utils import configuration as cfg


class Main:

    def __init__(self):
        QtGui.QIcon.setThemeSearchPaths(styles.QLiSPIconsThemePaths)
        QtGui.QIcon.setThemeName(styles.QLiSPIconsThemeName)

        self.mainWindow = MainWindow()
        self.collector = Collector()
        self.collectorUi = None
        self.programConf = {}

        self.mainWindow.newProgramAction.connect(self.newProgram)
        self.mainWindow.saveProgramAction.connect(self.saveProgram)
        self.mainWindow.openProgramAction.connect(self.openProgram)
        self.mainWindow.addMediaAction.connect(self.addMedia)
        self.mainWindow.editModeAction.connect(self.editMode)
        self.mainWindow.multiEditAction.connect(self.multiEdit)
        self.mainWindow.selectAllAction.connect(self.selectAll)
        self.mainWindow.deselectAllAction.connect(self.deselectAll)
        self.mainWindow.invertSelectionAction.connect(self.invertSelection)

        if(cfg.config['Layout']['UseDefault'] == 'True'):
            self.createLayout(cfg.config['Layout']['Default'])
        else:
            self.mainWindow.setEnabled(False)
            while(not self.layoutDialog()):
                pass
            self.mainWindow.setEnabled(True)

        self.collectorUi.onWidgetRemoved.connect(self.removeMedia)

        try:
            self.plugins = plugin.initPlugins(self)
        except Exception as e:
            QtGui.QMessageBox.critical(None, 'Error Message', ' '.join([str(i) for i in e.args]))

    def layoutDialog(self):
        select = LayoutSelect()
        select.exec_()
        if(select.result() == QtGui.QDialog.Accepted):
            self.createLayout(select.getSlected())
            return True
        else:
            return False

    def createLayout(self, lay):
        self.mainWindow.menuLayout.clear()
        if(self.collectorUi is not None):
            self.collectorUi.destroyLayout()
        self.collectorUi = layout.buildLayout(lay, self, parent=self.mainWindow.centralwidget)
        self.mainWindow.setProgramLayout(self.collectorUi)
        self.programConf['layout'] = lay

    def addMedia(self, files):
        try:
            for file in files:
                media = self.collectorUi.getMediaClass()()
                self.collector.addMedia(media)

                conf = deepcopy(self.collectorUi.MEDIA_DEFAULT_CONF)
                conf['location'] = file
                conf['name'] = file.split('/')[len(file.split('/')) - 1]

                self.collectorUi.addMediaWidget(media).setMediaConf(conf)
        except Exception as e:
            QtGui.QMessageBox.critical(None, 'Error Message', ' '.join([str(i) for i in e.args]))

    def removeMedia(self, media):
        if(isinstance(media, Media)):
            self.collector.removeMedia(media)

    def editMode(self, mode):
        QMediaWidget.MODE_EDIT = mode
        if not mode:
            for wMedia in self.collectorUi.mediaList():
                if wMedia is not None:
                    if wMedia.selected:
                        wMedia.select()

    def selectAll(self):
        for wMedia in self.collectorUi.mediaList():
            if wMedia is not None:
                if not wMedia.selected:
                    wMedia.select()

    def deselectAll(self):
        for wMedia in self.collectorUi.mediaList():
            if wMedia is not None:
                if wMedia.selected:
                    wMedia.select()

    def invertSelection(self):
        for wMedia in self.collectorUi.mediaList():
            if wMedia is not None:
                wMedia.select()

    def multiEdit(self, conf):
        for wMedia in self.collectorUi.mediaList():
            if(wMedia is not None):
                if(wMedia.selected):
                    if(wMedia.media.state == Media.NONE):
                        new_conf = deepcopy(self.collectorUi.MEDIA_DEFAULT_CONF)
                    else:
                        new_conf = wMedia.getMediaConf()
                    new_conf.update(conf)
                    wMedia.setMediaConf(new_conf)

    def playByPos(self, pos):
        wMedia = self.collectorUi.mediaAt(pos)
        if(wMedia is not None):
            wMedia.media.play()

    def stopByPos(self, pos):
        wMedia = self.collectorUi.mediaAt(pos)
        if(wMedia is not None):
            wMedia.media.stop()

    def pauseByPos(self, pos):
        wMedia = self.collectorUi.mediaAt(pos)
        if(wMedia is not None):
            wMedia.media.pause()

    def seekByPos(self, pos, time_ms):
        wMedia = self.collectorUi.mediaAt(pos)
        if(wMedia is not None):
            wMedia.media.seek(time_ms)

    def newProgram(self):
        self.collectorUi.destroyLayout()
        self.collector.resetCollector()
        self.collectorUi = None
        self.mainWindow.file = ''
        self.layoutDialog()
        self.resetPlugin()

    def saveProgram(self, filepath):
        writer = xml_writer.XmlWriter(filepath)
        for widget in self.collectorUi.mediaList():
            if(widget is not None):
                if(widget.media.state != Media.NONE):
                    writer.appendMedia(widget.getMediaConf())
                elif(self.collectorUi.SUPPORT_EMPTY_MEDIA):
                    writer.appendMedia(self.collectorUi.emptyMediaSaveConf(widget))

        writer.appendProgramSettings(self.programConf)

        for plug in self.plugins:
            data = self.getPluginData(plug)
            if(data is not None):
                writer.appendPluginSettings(plug.PLUGIN_NAME, data)

        writer.writeFile()

    def openProgram(self, filepath):
        progress = Progress(title='Loading ' + filepath)
        progress.show()
        try:
            progress.setLabelText('Reading file ...')
            reader = xml_reader.XmlReader(filepath)
            conf = reader.readMediaList()
            progress.setMaximum(len(conf) + 10)
            pluginsConf = reader.readPluginsSettings()
            self.programConf = reader.readProgramSettings()

            progress.setLabelText('Creating layout ...')
            self.createLayout(self.programConf['layout'])
            self.mainWindow.update()
            progress.setValue(progress.value() + 5)

            progress.setLabelText('Loading media ...')
            pfunct = lambda w: progress.setValue(progress.value() + 1)
            self.collectorUi.onWidgetAdded.connect(pfunct)
            self.collectorUi.readProgramConf(conf)
            self.collectorUi.onWidgetAdded.disconnect(pfunct)

            progress.setLabelText('Loading plugins ...')
            self.setPluginsData(pluginsConf)
            self.reloadPlugins()
            progress.hide()
        except Exception as e:
            progress.hide()
            QtGui.QMessageBox.critical(None, 'Error Message', 'Error during file reading: ' + ' '.join([str(i) for i in e.args]))
            self.newProgram()

    def setPluginsData(self, conf, debug=False):
        for plug in self.plugins:
            if(plug.PLUGIN_NAME in conf):
                if(debug):
                    plug.setData(conf[plug.PLUGIN_NAME])
                else:
                    try:
                        plug.setData(conf[plug.PLUGIN_NAME])
                    except:
                        raise Exception('Plugin data read failed: ' + plug.PLUGIN_NAME)

    def reloadPlugins(self, debug=False):
        for plug in self.plugins:
            if(debug):
                plug.reload()
            else:
                try:
                    plug.reload()
                except:
                    raise Exception('Plugin load failed: ' + plug.PLUGIN_NAME)

    def resetPlugin(self, debug=False):
        for plug in self.plugins:
            if(debug):
                plug.reset()
            else:
                try:
                    plug.reset()
                except:
                    raise Exception('Plugin reset failed: ' + plug.PLUGIN_NAME)

    def getPluginData(self, plugin, debug=False):
        if(debug):
            return plugin.getData()
        else:
            try:
                return plugin.getData()
            except:
                raise Exception('Plugin data save failed: ' + plugin.PLUGIN_NAME)


def main():
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName('Linux Show Player (beta version)')
    app.setQuitOnLastWindowClosed(True)
    # Force light font, for environment with bad QT support.
    appFont = app.font()
    appFont.setWeight(QtGui.QFont.Light)
    app.setFont(appFont)

    appMain = Main()  # @UnusedVariable

    GObject.threads_init()
    Gst.init(None)

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
